#include <errno.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include <sys/shm.h>

#include <stdio.h>
#include <fcntl.h>


#define BUF_SIZE 1024


int main( int argc, char **argv)
{
	if ( argc != 1)
	{
		printf("Wrong arguments\n");
		exit(0);
	}
	
	int fd =  open( ".for_keys", O_CREAT | 0644);
	if ( fd != -1)
		close(fd);
///////////////////////////////////////////////
	key_t key_sem_common  = ftok( ".for_keys", 1);
	key_t key_shm_common  = ftok( ".for_keys", 2);
///////////
	int sem_id_common = semget( key_sem_common ,2,IPC_CREAT | 0644);
///////////////
	int shm_id_common = shmget( key_shm_common, 9*sizeof( char), IPC_CREAT |  0644);	
///////////////
	int  * ptr_shm_common = (int* ) shmat( shm_id_common, NULL, NULL);
////////////////////////////////////////////////		
	struct sembuf sem_full_inc;
	sem_full_inc.sem_num =  1;    sem_full_inc.sem_op  =  2;   sem_full_inc.sem_flg = NULL;
	
	struct sembuf sem_full_dec;
	sem_full_dec.sem_num = 1;    sem_full_dec.sem_op = -2;   sem_full_dec.sem_flg = NULL;
	
	struct sembuf sem_empty_inc;
	sem_empty_inc.sem_num =  0;    sem_empty_inc.sem_op  =  2;   sem_empty_inc.sem_flg = NULL;
	
	struct sembuf sem_empty_dec;
	sem_empty_dec.sem_num = 0;    sem_empty_dec.sem_op = -2;  sem_empty_dec.sem_flg = NULL;
	
////////////////////////////////////////////////
	struct sembuf sem_buf[10];
		sem_buf[0].sem_num = 0;    sem_buf[0].sem_op =  0;  sem_buf[0].sem_flg = NULL;
		sem_buf[1].sem_num = 1;    sem_buf[1].sem_op =  0;  sem_buf[1].sem_flg = NULL;
		sem_buf[2].sem_num = 0;    sem_buf[2].sem_op =  2;  sem_buf[2].sem_flg = SEM_UNDO;
		sem_buf[3].sem_num = 1;    sem_buf[3].sem_op =  1;  sem_buf[3].sem_flg = SEM_UNDO;

	semop ( sem_id_common, sem_buf,4);
	
	
	semop ( sem_id_common, &sem_full_dec,1);
			char file_name[9];
			strcpy( file_name, ptr_shm_common);			
////////////////////////
	sem_buf[0].sem_num = 0;    sem_buf[0].sem_op =   2;  sem_buf[0].sem_flg = NULL;
	sem_buf[1].sem_num = 0;    sem_buf[1].sem_op =  -2;  sem_buf[1].sem_flg = SEM_UNDO;
	sem_buf[2].sem_num = 1;    sem_buf[2].sem_op =  -1;  sem_buf[2].sem_flg = SEM_UNDO;
	
	semop ( sem_id_common, sem_buf,3);
////////////////////////////////////////////////
	key_t key_sem  = ftok( file_name,1);
	
	key_t key_shm_buffer	   = ftok( file_name,2);
	key_t key_shm_count        = ftok( file_name,3);
///////
	int sem_id  = semget( key_sem ,3,IPC_CREAT | 0644);
	
	int shm_id_buffer = shmget( key_shm_buffer , BUF_SIZE      , IPC_CREAT | 0644);
	int shm_id_count  = shmget( key_shm_count  , sizeof(int)   , IPC_CREAT | 0644);
	
	char * ptr_shm_buffer = (char*) shmat( shm_id_buffer, NULL, SHM_RDONLY);
	int  * ptr_shm_count  = (int* ) shmat( shm_id_count , NULL, SHM_RDONLY);

	int fd_out = 1; //stdout
////////
	sem_buf[0].sem_num = 0;    sem_buf[0].sem_op =  3;   sem_buf[0].sem_flg = NULL;
	sem_buf[1].sem_num = 0;    sem_buf[1].sem_op = -3;   sem_buf[1].sem_flg = SEM_UNDO;
	sem_buf[2].sem_num = 0;    sem_buf[2].sem_op =  2;   sem_buf[2].sem_flg = NULL;
	
	semop( sem_id, sem_buf, 3);	
	do
	{
		semop( sem_id, &sem_full_dec,1);
			if ( semctl( sem_id, 1, GETVAL) != 0)
			{
				printf("Reader is killed\n");
				exit(0);
			}
	
			int write_count = 0;
			do
			{
				int tmp = write( fd_out, ptr_shm_buffer + write_count, *ptr_shm_count - write_count);
				if ( tmp == -1)
				{
					if ( errno == EINTR)
					{
						continue;
					}else
					{
						perror("Out write error");
						exit(0); 
					}
				}
				else
				{
					write_count +=tmp;
				}
			}
			while ( write_count != *ptr_shm_count);
		semop( sem_id, &sem_empty_inc,1);
	}
	while( *ptr_shm_count != 0);
//////////////////////////////////////
	shmdt( ptr_shm_common);
	shmdt( ptr_shm_buffer);
	shmdt( ptr_shm_count);
}
